package com.zmj.sy.mom.srv.aps.service;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.order.ApsOrder;
import com.zmj.sy.mom.srv.aps.bean.entity.order.ApsWorkOrder;
import com.zmj.sy.mom.srv.aps.bean.entity.order.Order;
import com.zmj.sy.mom.srv.aps.bean.entity.order.OrderBom;
import com.zmj.sy.mom.srv.aps.bean.vo.aps.ApsWireStockCountReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.aps.ApsWireStockCountResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.aps.SelectConsVo;
import com.zmj.sy.mom.srv.aps.bean.vo.apsorderwork.ApsWorkOrderListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.apsorderwork.ApsWorkOrderTreeResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseIdReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BaseListResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.base.BasePageResVo;
import com.zmj.sy.mom.srv.aps.bean.vo.purchaseplan.ApsWorkOrderPurchaseExcelVo;
import com.zmj.sy.mom.srv.aps.bean.vo.purchaseplan.ApsWorkOrderPurchasePlanReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.purchaseplan.ApsWorkOrderPurchasePlanResVo;
import com.zmj.sy.mom.srv.aps.feign.WmsLtkApiClient;
import com.zmj.sy.mom.srv.aps.mapper.ApsOrderMapper;
import com.zmj.sy.mom.srv.aps.mapper.ApsWorkOrderMapper;
import com.zmj.sy.mom.srv.aps.mapper.OrderBomMapper;
import com.zmj.sy.mom.srv.aps.mapper.OrderMapper;
import com.zmj.sy.mom.srv.aps.utils.PkgUtils;
import com.zmj.sy.mom.srv.aps.utils.PoiUtils;
import feign.Request;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class ApsWorkOrderService {

    private final ApsWorkOrderMapper apsWorkOrderMapper;

    private final ApsOrderMapper apsOrderMapper;
    private final OrderMapper orderMapper;
    private final WmsLtkApiClient wmsLtkApiClient;
    private final OrderBomMapper orderBomMapper;

    public BaseListResVo<ApsWorkOrderTreeResVo> tree(BaseIdReqVo reqVo) {

        List<ApsOrder> apsOrders = apsOrderMapper.selectList(Wrappers.<ApsOrder>lambdaQuery().eq(ApsOrder::getOrderId, reqVo.getId()));
        Order order = orderMapper.selectById(reqVo.getId());
        LambdaQueryWrapper<ApsWorkOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ApsWorkOrder::getApsOrderId, apsOrders.stream().map(BaseEntity::getId).collect(Collectors.toList()));
        List<ApsWorkOrder> apsWorkOrders = apsWorkOrderMapper.selectList(wrapper);
        List<ApsWorkOrderTreeResVo> apsOrderList = apsOrders.stream()
                .sorted(Comparator.comparing(ApsOrder::getSeq))
                .map(e -> {
                    ApsWorkOrderTreeResVo rr = new ApsWorkOrderTreeResVo();
                    rr.setId(-e.getId());
                    rr.setPid(0);
                    if(e.getPlanStartDateTime() != null){
                        rr.setMaterCode("[" + e.getPlanStartDateTime().toLocalDate().toString() + "至"+  e.getPlanEndDateTime().toLocalDate().toString() + "]");

                    }
                    rr.setMaterName(PkgUtils.gen(e.getSeq()));
                    rr.setTreeType(1);
                    rr.setWorkOrderCode(order.getSerialCode());
                    rr.setOrderQty(e.getOrderQty());
                    rr.setPlanEndDateTime(e.getPlanEndDateTime());
                    return rr;
                })
                .collect(Collectors.toList());

        Map<Integer, ApsWorkOrderTreeResVo> collect = apsOrderList.stream().collect(Collectors.toMap(ApsWorkOrderTreeResVo::getId, Function.identity()));

        List<ApsWorkOrder> collect1 = apsWorkOrders.stream().filter(e -> e.getPid() == null).collect(Collectors.toList());
        for (ApsWorkOrder e : collect1) {
            e.setPid(collect.get(-e.getApsOrderId()).getId());
        }

        BaseListResVo<ApsWorkOrderTreeResVo> apsWorkOrderTreeResVoBaseListResVo = BaseListResVo.of(apsWorkOrders, ApsWorkOrderTreeResVo.class);
        for (ApsWorkOrderTreeResVo datum : apsWorkOrderTreeResVoBaseListResVo.getData()) {
            datum.setTreeType(2);
        }
        apsWorkOrderTreeResVoBaseListResVo.getData().addAll(apsOrderList);


        ApsWorkOrderTreeResVo orderRes = new ApsWorkOrderTreeResVo();
        orderRes.setPid(null);
        orderRes.setId(0);
        orderRes.setMaterName(order.getSerialCode());
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        if (order.getPlanStartDateTime() != null) {
            sb.append(order.getPlanStartDateTime().toLocalDate().toString());
        }
        sb.append("至");

        if (order.getPlanEndDateTime() != null) {
            sb.append(order.getPlanEndDateTime().toLocalDate().toString());
        }
        sb.append("]");

        orderRes.setMaterCode(sb.toString());
        orderRes.setTreeType(1);
        orderRes.setPlanEndDateTime(order.getPlanEndDateTime());
        orderRes.setOrderQty(order.getOrderQty());
        apsWorkOrderTreeResVoBaseListResVo.getData().add(0, orderRes);
        return apsWorkOrderTreeResVoBaseListResVo;
    }

    public BaseListResVo<ApsWorkOrderListResVo> list(BaseIdReqVo reqVo) {

        LambdaQueryWrapper<ApsWorkOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(ApsWorkOrder::getId, reqVo.getId());
        wrapper.or();
        wrapper.eq(ApsWorkOrder::getPid, reqVo.getId());
//        wrapper.ne(ApsWorkOrder::getWorkChain, "WL");

        wrapper.orderByAsc(ApsWorkOrder::getPid);
        wrapper.orderByAsc(ApsWorkOrder::getMaterCode);
        List<ApsWorkOrder> apsWorkOrders = apsWorkOrderMapper.selectList(wrapper);

        return BaseListResVo.of(apsWorkOrders, ApsWorkOrderListResVo.class);
    }

    public BasePageResVo<ApsWorkOrderPurchasePlanResVo> purchasePlan(ApsWorkOrderPurchasePlanReqVo reqVo) {

        QueryWrapper<ApsWorkOrder> wrapper = Wrappers.query();
        wrapper.eq("awo.work_chain", "WL");
        wrapper.in("o.order_type", 1, 3, 4);

//        wrapper.ge("awo.status", 2);
//        wrapper.notLike("awo.plm_id", "010%");
//        wrapper.notLike("awo.plm_id", "020%");
//        wrapper.notLike("awo.plm_id", "050%");

        if (CollUtil.isNotEmpty(reqVo.getComponentType())) {
            Map<String, Integer> map = new HashMap<>();
            map.put("顶梁", 1);
            map.put("掩护梁", 2);
            map.put("底座", 3);
            map.put("侧板", 4);
            map.put("连杆", 5);

            // map 的key和value互换
            List<String> collect = map.entrySet().stream().filter(e -> reqVo.getComponentType().contains(e.getValue())).map(Map.Entry::getKey).distinct().collect(Collectors.toList());

            wrapper.and(wr -> {
                for (String s : collect) {
                    wr.or().like("o.mater_name", s);
                }
            });
        }



        wrapper.like(StringUtils.hasText(reqVo.getPaintCode()), " awo.drawing ", reqVo.getPaintCode());
        wrapper.like(StringUtils.hasText(reqVo.getMaterName()), " awo.mater_name ", reqVo.getMaterName());
        wrapper.like(StringUtils.hasText(reqVo.getPlmId()), " awo.plm_id ", reqVo.getPlmId());
        wrapper.like(StringUtils.hasText(reqVo.getParentPlmId()), " tob.plm_id ", reqVo.getParentPlmId());
        wrapper.like(StringUtils.hasText(reqVo.getConstructNo()), " o.construct_no ", reqVo.getConstructNo());


        wrapper.ge(StringUtils.hasText(reqVo.getStartDate()), " DATE_FORMAT( awo.plan_start_date_time, '%Y-%m-%d' ) ", reqVo.getStartDate());
        wrapper.le(StringUtils.hasText(reqVo.getEndDate()), " DATE_FORMAT( awo.plan_start_date_time, '%Y-%m-%d' ) ", reqVo.getEndDate());

        wrapper.groupBy("o.construct_no, o.mater_code, o.mater_name, awo.drawing, tob.plm_id, awo.plm_id, awo.mater_name, awo.standards, awo.erp_code ");
        wrapper.orderByAsc(" o.mater_code, tob.plm_id DESC, min(awo.plan_start_date_time), awo.plm_id ");
        Page<ApsWorkOrderPurchasePlanResVo> page = apsWorkOrderMapper.purchasePlan(wrapper, reqVo.toPage());

        List<String> collect = page.getRecords().stream().map(ApsWorkOrderPurchasePlanResVo::getPlmId).distinct().collect(Collectors.toList());
        ApsWireStockCountReqVo ltkVo = new ApsWireStockCountReqVo();
        ltkVo.setMaterCodeList(collect);
        List<ApsWireStockCountResVo> ltkList = null;
        try {
            Request.Options options = new Request.Options(5L, TimeUnit.SECONDS, 5L, TimeUnit.SECONDS, true);
            ltkList = wmsLtkApiClient.stockCount(ltkVo, options);
        } catch (Exception e) {
            ltkList = new ArrayList<>();
        }

        Map<String, Integer> ltkMap = ltkList.stream().collect(Collectors.toMap(ApsWireStockCountResVo::getMaterCode, ApsWireStockCountResVo::getTotalCount));

        for (ApsWorkOrderPurchasePlanResVo record : page.getRecords()) {
            Integer count = ltkMap.getOrDefault(record.getPlmId(), 0);
            record.setStockCount(new BigDecimal(count));
            record.setPurchaseCount(record.getDemandCount().subtract(record.getPickCount()));
        }
        return BasePageResVo.of(page, ApsWorkOrderPurchasePlanResVo.class);

    }

    @Transactional(readOnly = true)
    @SneakyThrows
    public Workbook exportExcel(ApsWorkOrderPurchaseExcelVo reqVo) {

        Map<Integer, String> map = new HashMap<>();
        map.put(1, "顶梁");
        map.put(2, "掩护梁");
        map.put(3, "底座");
        map.put(4, "侧板");
        map.put(5, "连杆");

        if (CollUtil.isEmpty(reqVo.getComponentType())) {
            List<Integer> typeList = Lists.newArrayList(1, 2, 3, 4, 5);
            reqVo.setComponentType(typeList);
        }

        Workbook workbook = new XSSFWorkbook();

        Sheet sheet = workbook.createSheet("外购件领料单");
        sheet.setColumnWidth(0, 256 * 5);
        sheet.setColumnWidth(1, 256 * 24);
        sheet.setColumnWidth(2, 256 * 24);
        sheet.setColumnWidth(3, 256 * 7);
        sheet.setColumnWidth(4, 256 * 7);
        sheet.setColumnWidth(5, 256 * 7);
        sheet.setColumnWidth(6, 256 * 12);


        int currentRowIndex = 0;
        for (Integer type : reqVo.getComponentType()) {

            Order order = orderMapper.lambdaQuery()
                    .like(Order::getMaterName, map.get(type))
                    .eq(Order::getConstructNo, reqVo.getConstructNo())
                    .in(Order::getOrderType, 1, 3, 4)
                    .one();

            if (ObjectUtils.isEmpty(order)) {
                continue;
            }

            QueryWrapper<ApsWorkOrder> wrapper = Wrappers.query();
            wrapper.eq("awo.work_chain", "WL");
            wrapper.eq(" o.id ", order.getId());

            wrapper.groupBy(" awo.mater_code, awo.mater_name, tob.id ");
            wrapper.orderByAsc(" tob.id, awo.mater_code ");
            List<ApsWorkOrderPurchasePlanResVo> voList = apsWorkOrderMapper.exportExcel(wrapper);
            Map<Integer, List<ApsWorkOrderPurchasePlanResVo>> voMap = voList.stream().collect(Collectors.groupingBy(ApsWorkOrderPurchasePlanResVo::getTobId));

            if (CollUtil.isEmpty(voList)) {
                continue;
            }

            int indexAdd = currentRowIndex++;
            int firstCol = 0;
            int lastCol = 6;
            CellRangeAddress region = new CellRangeAddress(indexAdd, indexAdd, firstCol, lastCol);

            sheet.addMergedRegion(region);

            PoiUtils.cells(workbook, sheet, indexAdd, true, String.format("%s(%s)%s外来件计划", order.getConstructNo(), order.getOrderQty(), map.get(type)), "", "", "", "", "", "");
            PoiUtils.cells(workbook, sheet, currentRowIndex++, true, "序号", "图号", "名称", "数量", "入", "出", "领料人签名");

            List<Integer> idList = voList.stream().map(ApsWorkOrderPurchasePlanResVo::getTobId).collect(Collectors.toList());
            List<OrderBom> orderBomList = orderBomMapper.selectBatchIds(idList);

            orderBomList.sort(Comparator.comparing(OrderBom::getId));

            for (OrderBom orderBom : orderBomList) {
                List<ApsWorkOrderPurchasePlanResVo> listVo = voMap.get(orderBom.getId());

                if (CollUtil.isEmpty(listVo)) {
                    continue;
                }

                int indexAdd2 = currentRowIndex++;
                CellRangeAddress region2 = new CellRangeAddress(indexAdd2, indexAdd2, firstCol, lastCol);

                sheet.addMergedRegion(region2);
                PoiUtils.cells(workbook, sheet, indexAdd2, true, orderBom.getMaterName(),"","","","","","");

                for (int i = 0; i < listVo.size(); i++) {
                    ApsWorkOrderPurchasePlanResVo r = listVo.get(i);
                    PoiUtils.cells(workbook, sheet, currentRowIndex++, false, (i+1) + "", r.getPlmId(), r.getMaterName(), r.getDemandCount().intValue() + "", "", "", "");
                }

                int indexAdd23 = currentRowIndex++;
                CellRangeAddress region3 = new CellRangeAddress(indexAdd23, indexAdd23, firstCol, lastCol);
                sheet.addMergedRegion(region3);
                PoiUtils.cells(workbook, sheet, indexAdd23, false, "", "", "", "", "", "", "");

            }

        }

        return workbook;
    }

    public BaseListResVo<SelectConsVo> selectCon(SelectConsVo reqVo) {
        List<Order> orderList = orderMapper.lambdaQuery()
                .like(StringUtils.hasText(reqVo.getConstructCode()), Order::getConstructNo, reqVo.getConstructCode())
                .orderByDesc(Order::getCreateDateTime)
                .last(" LIMIT 30")
                .list();
        List<String> collect = orderList.stream().map(Order::getConstructNo).distinct().collect(Collectors.toList());
        List<SelectConsVo> voList = collect.stream().map(e -> {
            SelectConsVo selectConsVo = new SelectConsVo();
            selectConsVo.setConstructCode(e);
            return selectConsVo;
        }).collect(Collectors.toList());
        return BaseListResVo.of(voList, SelectConsVo.class);
    }

}
